/* ****************************************************************************
* Copyright (c) TCC - 2009 IME - USP. 
*
* This source code is subject to terms and conditions of the Microsoft Public License. 
* A copy of the license can be found in http://msdn.microsoft.com/en-us/library/dd228915.aspx. 
* By using this source code in any fashion, you are agreeing to be bound by the terms of the 
* Microsoft Public License.
*
* You must not remove this notice, or any other, from this software.
* ***************************************************************************/

namespace SoundLibrary
{

    public class Equalizer
    {
        #region Properties
        public virtual float[] FromFloatArray
        {
            set
            {
                reset();
                int max = (value.Length > BANDS) ? BANDS : value.Length;

                for (int i = 0; i < max; i++)
                {
                    settings[i] = limit(value[i]);
                }
            }

        }

        public virtual Equalizer FromEqualizer
        {
            set
            {
                if (value != this)
                {
                    FromFloatArray = value.settings;
                }
            }

        }

        public virtual EQFunction FromEQFunction
        {
            set
            {
                reset();
                int max = BANDS;

                for (int i = 0; i < max; i++)
                {
                    settings[i] = limit(value.getBand(i));
                }
            }
        }

        public virtual int BandCount
        {
            get
            {
                return settings.Length;
            }
        }

        internal virtual float[] BandFactors
        {
            get
            {
                float[] factors = new float[BANDS];
                for (int i = 0, maxCount = BANDS; i < maxCount; i++)
                {
                    factors[i] = getBandFactor(settings[i]);
                }

                return factors;
            }
        }
        #endregion

        public static readonly float BAND_NOT_PRESENT = System.Single.NegativeInfinity;
        public static readonly Equalizer PASS_THRU_EQ = new Equalizer();
        private const int BANDS = 32;
        private float[] settings;

        #region Constructors
        public Equalizer()
        {
            InitBlock();
        }


        ////  private Equalizer(float b1, float b2, float b3, float b4, float b5,
        ////                      float b6, float b7, float b8, float b9, float b10, float b11,
        ////                      float b12, float b13, float b14, float b15, float b16,
        ////                      float b17, float b18, float b19, float b20);

        public Equalizer(float[] settings)
        {
            InitBlock();
            FromFloatArray = settings;
        }

        public Equalizer(EQFunction eq)
        {
            InitBlock();
            FromEQFunction = eq;
        }
        #endregion

        #region Public Methods
        public void reset()
        {
            for (int i = 0; i < BANDS; i++)
            {
                settings[i] = 0.0f;
            }
        }

        public float setBand(int band, float neweq)
        {
            float eq = 0.0f;

            if ((band >= 0) && (band < BANDS))
            {
                eq = settings[band];
                settings[band] = limit(neweq);
            }

            return eq;
        }

        public float getBand(int band)
        {
            float eq = 0.0f;

            if ((band >= 0) && (band < BANDS))
            {
                eq = settings[band];
            }

            return eq;
        }
        #endregion

        #region Private Methods
        private void InitBlock()
        {
            settings = new float[BANDS];
        }

        private float limit(float eq)
        {
            if (eq == BAND_NOT_PRESENT)
            {
                return eq;
            }
            if (eq > 1.0f)
            {
                return 1.0f;
            }
            if (eq < -1.0f)
            {
                return -1.0f;
            }

            return eq;
        }
        #endregion

        #region Internal Methods
        internal float getBandFactor(float eq)
        {
            if (eq == BAND_NOT_PRESENT)
            {
                return 0.0f;
            }

            float f = (float)System.Math.Pow(2.0, eq);
            return f;
        }
        #endregion

        abstract public class EQFunction
        {
            public virtual float getBand(int band)
            {
                return 0.0f;
            }
        }
    }
}